package com.shengqin.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shengqin.calculate.data.CalculateContext;
import com.shengqin.calculate.data.CalculateSummaryModel;
import com.shengqin.calculate.data.ErrorLogModel;
import com.shengqin.calculate.data.UpdateParentResultModel;
import com.shengqin.calculate.events.CalculateLogEvent;
import com.shengqin.calculate.events.CalculateSummaryEvent;
import com.shengqin.calculate.events.UpdateParentResultEvent;
import com.shengqin.calculate.service.CalculateService;
import com.shengqin.common.pojo.CommonPage;
import com.shengqin.config.CommonException;
import com.shengqin.config.model.TestProjectConfig;
import com.shengqin.controller.api.dto.UploadScoreItem;
import com.shengqin.entity.*;
import com.shengqin.mapper.TestResultMapper;
import com.shengqin.pojo.plan.PlanQueryParam;
import com.shengqin.pojo.plan.result.ImportTestResultParam;
import com.shengqin.pojo.plan.result.ScoreQueryResult;
import com.shengqin.pojo.plan.result.ScoreResult;
import com.shengqin.pojo.plan.result.TestResultKey;
import com.shengqin.pojo.summary.SummaryModel;
import com.shengqin.pojo.summary.SummaryQueryParam;
import com.shengqin.service.*;
import com.shengqin.utils.GradeUtil;
import com.shengqin.utils.ProjectUtil;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.test.Test;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * <p>
 * 成绩 服务实现类
 * </p>
 *
 * @author Rui.Zhou
 * @since 2023-12-11
 */
@Service
@Slf4j
public class TestResultServiceImpl extends ServiceImpl<TestResultMapper, TestResult> implements ITestResultService {

    @Resource
    private ISchoolService schoolService;
    @Resource
    private IPlanStudentService planStudentService;
    @Resource
    private IStandardService standardService;
    @Resource
    private IPlanService planService;
    @Resource
    private SysHealthProjectService healthProjectService;
    @Resource
    private ISummaryResultService summaryResultService;
    @Resource
    private TestProjectConfig testProjectConfig;
    @Resource
    private CalculateService calculateService;
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private ICalculateLogService calculateLogService;

    private static final DecimalFormat decimalFormat = new DecimalFormat("#0.00");

    @Override
    public Page<TestResult> getPage(CommonPage<TestResult> queryPage) {
        TestResult testResult = queryPage.getQueryParam();
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        if (testResult.getSchoolId() != null) {
            wrapper.lambda().eq(TestResult::getSchoolId, testResult.getSchoolId());
        }
        if (StringUtils.hasLength(testResult.getName())) {
            wrapper.lambda().eq(TestResult::getName, testResult.getName());
        }
        if (StringUtils.hasLength(testResult.getStudyCode())) {
            wrapper.lambda().eq(TestResult::getStudyCode, testResult.getStudyCode());
        }
        if (StringUtils.hasLength(testResult.getSex())) {
            wrapper.lambda().eq(TestResult::getSex, testResult.getSex());
        }
        if (StringUtils.hasLength(testResult.getPrjCode())) {
            wrapper.lambda().eq(TestResult::getPrjCode, testResult.getPrjCode());
        }
        if (StringUtils.hasLength(testResult.getPrjName())) {
            wrapper.lambda().like(TestResult::getPrjName, testResult.getPrjName());
        }
        if (testResult.getGradeId() != null) {
            wrapper.lambda().eq(TestResult::getGradeId, testResult.getGradeId());
        }
        if (StringUtils.hasLength(testResult.getTestStartTime()) && StringUtils.hasLength(testResult.getTestEndTime())) {
            wrapper.lambda().ge(TestResult::getTestStartTime, testResult.getTestStartTime());
            wrapper.lambda().le(TestResult::getTestEndTime, testResult.getTestEndTime());
        }
        wrapper.lambda().eq(TestResult::getPlanId, testResult.getPlanId());
        wrapper.lambda().orderByDesc(TestResult::getId);
        Page<TestResult> testResultPage = new Page<>(queryPage.getPageNo(), queryPage.getPageSize());
        page(testResultPage, wrapper);
        buildRecords(testResultPage.getRecords());
        return testResultPage;
    }

    private void calculateTestResult(List<ImportTestResultParam> testDataList, Integer planId, String type) {
        ErrorLogModel errorLogModel = new ErrorLogModel();
        errorLogModel.setPlanId(planId);
        errorLogModel.setType(type);
        try {
            errorLogModel.setReqParam(JSON.toJSONString(testDataList));
            Plan plan = planService.getById(planId);
            Integer templateId = plan.getTemplateId();

            if (templateId == null) {
                throw new CommonException("计划未绑定评分模板，请检查！");
            }

            Set<String> studyCodes = new HashSet<>();
            testDataList.forEach(testResult -> {
                if (StringUtils.hasLength(testResult.getStudyCode())) {
                    studyCodes.add(testResult.getStudyCode());
                }
            });

            if (CollectionUtils.isEmpty(studyCodes)) {
                throw new CommonException("成绩数据中没有学籍号信息，请检查！");
            }

            List<PlanStudent> students = planStudentService.queryByPlanIdAndStudyCodes(planId, studyCodes);

            if (plan.getExamFlag()!=null && plan.getExamFlag() && CollectionUtils.isEmpty(students)) {
                throw new CommonException("该计划里考生数据可能未导入，请检查");
            }
            Map<String, PlanStudent> studentMap = students.stream().collect(Collectors.toMap(PlanStudent::getStudyCode, s -> s));

            List<Standard> templateStandardList = standardService.listByTemplateId(templateId);
            if (CollectionUtils.isEmpty(templateStandardList)) {
                throw new CommonException("评分模板中没有设置评分标准数据，请检查！");
            }

            List<SysHealthProject> templateProjects = healthProjectService.listByTemplateId(templateId);
            if (CollectionUtils.isEmpty(templateProjects)) {
                throw new CommonException("评分模板中没有设置项目数据，请检查！");
            }

            Map<TestResultKey, List<Standard>> standardMap = templateStandardList.stream().collect(Collectors.groupingBy(t -> new TestResultKey(t.getProjectName(), t.getSex(), t.getGradeId())));
            Map<String, SysHealthProject> projectMap = templateProjects.stream().collect(Collectors.toMap(t -> t.getProjectName() + "_" + t.getGradeId(), p -> p));


            List<TestResult> testDataResultList = buildTestResults(testDataList, studentMap);
            Map<String, List<TestResult>> studyTestDataResultMap = testDataResultList.stream().filter(item -> StringUtils.hasLength(item.getPrjName())).collect(Collectors.groupingBy(TestResult::getStudyCode));

            List<TestResult> oldTestResults = listByPlanIdAndStudyCodes(planId, studyCodes);
            Map<String, List<TestResult>> oldTestResultMap = oldTestResults.stream().collect(Collectors.groupingBy(TestResult::getStudyCode));

            studyTestDataResultMap.forEach((studyCode, testResultList) -> {
                CalculateContext calculateContext = new CalculateContext();
                calculateContext.setPlan(plan);
                calculateContext.setUploadType(type);
                List<TestResult> heightWeightList = testResultList.stream().filter(t -> "身高".equals(t.getPrjName()) || "体重".equals(t.getPrjName())).collect(Collectors.toList());
                calculateContext.setHeightWeightTestResultList(heightWeightList);
                calculateContext.setAllTestResultList(testResultList);
                calculateContext.setStandardMap(standardMap);
                calculateContext.setProjectMap(projectMap);
                calculateContext.setAllOldTestResultList(oldTestResultMap.getOrDefault(studyCode, new ArrayList<>()));

                calculateService.execute(calculateContext);
                log.info("学籍号[{}]计算结果{}", studyCode, JSON.toJSONString(calculateContext.getCalculateResultList()));
                if (!CollectionUtils.isEmpty(calculateContext.getDeleteOldResultIdList())) {
                    removeBatchByIds(calculateContext.getDeleteOldResultIdList());
                    log.info("学籍号[{}]删除老成绩{}条", studyCode, calculateContext.getDeleteOldResultIdList().size());
                }
                if (!CollectionUtils.isEmpty(calculateContext.getCalculateResultList())) {
                    List<TestResult> waitSuccessList = new ArrayList<>();

                    Map<String, List<TestResult>> prjResultMap = calculateContext.getCalculateResultList().stream().collect(Collectors.groupingBy(TestResult::getPrjName));
                    prjResultMap.forEach((prjName, prjResults) -> waitSuccessList.add(prjResults.get(0)));

                    boolean saveSuccess = saveOrUpdateBatch(waitSuccessList);
                    if (saveSuccess) {
                        CalculateSummaryModel calculateSummaryModel = new CalculateSummaryModel();
                        calculateSummaryModel.setStudyCode(studyCode);
                        calculateSummaryModel.setPlan(plan);
                        applicationContext.publishEvent(new CalculateSummaryEvent(this, calculateSummaryModel));
                    }
                }

            });

            if (plan.getState() == 1) {
                plan.setState(2);
                planService.updateById(plan);
            }
            errorLogModel.setFlag(1);
        } catch (Exception e) {
            log.error("成绩计算报错", e);
            errorLogModel.setFlag(2);
            errorLogModel.setReason(e.getMessage());
        } finally {
            applicationContext.publishEvent(new CalculateLogEvent(this, errorLogModel));
        }

    }

    public List<TestResult> buildTestResultList(List<ResultRecord> resultRecords, Map<String, PlanStudent> studentMap) {
        List<TestResult> testResults = new ArrayList<>();
        resultRecords.forEach(resultRecord -> {
            PlanStudent student = studentMap.getOrDefault(resultRecord.getStudyCode(), null);
            if (student != null) {
                TestResult testResult = new TestResult();
                BeanUtils.copyProperties(student, testResult);
                testResult.setResult(resultRecord.getResult());
                testResult.setPrjName(resultRecord.getPrjName());
                testResult.setPrjCode(ProjectUtil.getPrjCode(resultRecord.getPrjName()));
                testResult.setDeviceNo(resultRecord.getDeviceNo());
                testResult.setTestEndTime(resultRecord.getTestEndTime());
                testResult.setTestStartTime(resultRecord.getTestStartTime());
                testResult.setCreateTime(LocalDateTime.now());
                testResult.setId(null);
                testResult.setCameraId(resultRecord.getCameraId());
                testResult.setResultRecordId(resultRecord.getId());

                if ("身高体重".equals(resultRecord.getPrjName())) {
                    testResults.addAll(buildBmiTestResult(resultRecord.getResult(), testResult));
                } else {
                    testResults.add(testResult);
                }

            } else {
                log.error("学籍号{}未导入考生信息里",resultRecord.getStudyCode());
            }
        });
        return testResults;
    }

    private List<TestResult> buildTestResults(List<ImportTestResultParam> cachedDataList, Map<String, PlanStudent> studentMap) {
        List<TestResult> testResults = new ArrayList<>();
        cachedDataList.forEach(importTestResultParam -> {
            PlanStudent student = studentMap.getOrDefault(importTestResultParam.getStudyCode(), null);
            if (student != null) {
                TestResult testResult = new TestResult();
                BeanUtils.copyProperties(student, testResult);
                testResult.setResult(importTestResultParam.getResult());
                testResult.setPrjName(importTestResultParam.getPrjName());
                testResult.setPrjCode(ProjectUtil.getPrjCode(importTestResultParam.getPrjName()));
                testResult.setDeviceNo(importTestResultParam.getDeviceNo());
                testResult.setTestEndTime(importTestResultParam.getTestEndTime());
                testResult.setTestStartTime(importTestResultParam.getTestStartTime());
                testResult.setCreateTime(LocalDateTime.now());
                testResult.setId(null);
                testResult.setCameraId(importTestResultParam.getCameraId());

                if ("身高体重".equals(importTestResultParam.getPrjName())) {
                    testResults.addAll(buildBmiTestResult(importTestResultParam, testResult));
                } else {
                    testResults.add(testResult);
                }

            }
        });
        return testResults;
    }

    public List<TestResult> buildBmiTestResult(String result, TestResult hwTestResult) {
        List<TestResult> testResults = new ArrayList<>();
        String[] heightAndWeight = result.split(" ");
        TestResult heightResult = new TestResult();
        BeanUtils.copyProperties(hwTestResult, heightResult);
        TestResult weightResult = new TestResult();
        BeanUtils.copyProperties(hwTestResult, weightResult);
        TestResult bmiResult = new TestResult();
        BeanUtils.copyProperties(hwTestResult, bmiResult);

        heightResult.setResult(heightAndWeight[0]);
        heightResult.setPrjName("身高");
        heightResult.setPrjCode("2");
        weightResult.setResult(heightAndWeight[1]);
        weightResult.setPrjName("体重");
        weightResult.setPrjCode("3");

        double w = Double.parseDouble(heightAndWeight[1]);
        Double h = Double.parseDouble(heightAndWeight[0]) / 100;

        double bmi = w / (h * h);
        bmiResult.setResult(decimalFormat.format(bmi));
        bmiResult.setPrjName("BMI");
        bmiResult.setPrjCode("4");

        testResults.add(bmiResult);
        testResults.add(heightResult);
        testResults.add(weightResult);
        return testResults;
    }

    private List<TestResult> buildBmiTestResult(ImportTestResultParam importTestResultParam, TestResult hwTestResult) {
        List<TestResult> testResults = new ArrayList<>();
        String result = importTestResultParam.getResult();
        String[] heightAndWeight = result.split(" ");
        TestResult heightResult = new TestResult();
        BeanUtils.copyProperties(hwTestResult, heightResult);
        TestResult weightResult = new TestResult();
        BeanUtils.copyProperties(hwTestResult, weightResult);
        TestResult bmiResult = new TestResult();
        BeanUtils.copyProperties(hwTestResult, bmiResult);

        heightResult.setResult(heightAndWeight[0]);
        heightResult.setPrjName("身高");
        heightResult.setPrjCode("2");
        weightResult.setResult(heightAndWeight[1]);
        weightResult.setPrjName("体重");
        weightResult.setPrjCode("3");

        double w = Double.parseDouble(heightAndWeight[1]);
        Double h = Double.parseDouble(heightAndWeight[0]) / 100;

        double bmi = w / (h * h);
        bmiResult.setResult(decimalFormat.format(bmi));
        bmiResult.setPrjName("BMI");
        bmiResult.setPrjCode("4");

        testResults.add(bmiResult);
        testResults.add(heightResult);
        testResults.add(weightResult);
        return testResults;
    }

    @Override
    public void importBatch(List<ImportTestResultParam> cachedDataList, Integer planId, String type) {
        try {
            calculateTestResult(cachedDataList, planId, type);
        } catch (Exception e) {
            log.error("导入成绩数据异常", e);
            throw e;
        }
    }

    @Override
    public List<TestResult> listByPlanParam(PlanQueryParam planQueryParam) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(TestResult::getPlanId, planQueryParam.getPlanId());
        if (planQueryParam.getSchoolId() != null) {
            wrapper.lambda().in(TestResult::getSchoolId, planQueryParam.getSchoolId());
        }
        wrapper.lambda().orderByAsc(TestResult::getGradeId).orderByAsc(TestResult::getClassesName);
        return list(wrapper);
    }

    @Override
    public List<SummaryModel> summary(SummaryQueryParam queryParam) {
        long planStudentCount;
        long freeTestCount = 0;
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(TestResult::getSchoolId, queryParam.getSchoolId());
        wrapper.lambda().notIn(TestResult::getPrjCode, "2", "3");
        if (queryParam.getPlanId() != null) {
            wrapper.lambda().eq(TestResult::getPlanId, queryParam.getPlanId());
            Plan plan = planService.getById(queryParam.getPlanId());
            planStudentCount = plan.getStudentNum();
//            freeTestCount = planStudentService.listFreeTestByPlanIdAndSchoolId(queryParam.getPlanId(),queryParam.getSchoolId());
        } else {
            planStudentCount = 0;
        }
        List<TestResult> testResultList = list(wrapper);
        Map<String, List<TestResult>> prjTestResultMap = testResultList.stream().collect(Collectors.groupingBy(TestResult::getPrjCode));
        if (planStudentCount == 0) {
            return new ArrayList<>();
        }

        List<SummaryModel> summaryModels = new ArrayList<>();
        prjTestResultMap.forEach((prjCode, testResults) -> {
            SummaryModel summaryModel = new SummaryModel();
            summaryModel.setDataKey(ProjectUtil.getPrjName(prjCode));
            summaryModel.setTotalCount((int) planStudentCount);
            summaryModel.setFreeTestCount((int) freeTestCount);
            summaryModel.setTestCount(testResults.size());
            AtomicReference<Integer> bestCount = new AtomicReference<>(0);
            AtomicReference<Integer> wellCount = new AtomicReference<>(0);
            AtomicReference<Integer> passCount = new AtomicReference<>(0);
            AtomicReference<Integer> noPassCount = new AtomicReference<>(0);

            if (!prjCode.equals("2") && !prjCode.equals("3")) {
                Map<String, List<TestResult>> levelMap = testResults.stream().collect(Collectors.groupingBy(TestResult::getLevel));
                if (prjCode.equals("4")) {
                } else {
                    bestCount.set(levelMap.getOrDefault("优秀", new ArrayList<>()).size());
                    wellCount.set(levelMap.getOrDefault("良好", new ArrayList<>()).size());
                    passCount.set(levelMap.getOrDefault("及格", new ArrayList<>()).size());
                    noPassCount.set(levelMap.getOrDefault("不及格", new ArrayList<>()).size());

                    BigDecimal totalSizeCount = new BigDecimal(planStudentCount + "");
                    BigDecimal percent = new BigDecimal("100");
                    summaryModel.setBestRate(new BigDecimal(bestCount.get()).divide(totalSizeCount, 4, RoundingMode.HALF_UP).multiply(percent));
                    summaryModel.setWellRate(new BigDecimal(wellCount.get()).divide(totalSizeCount, 4, RoundingMode.HALF_UP).multiply(percent));
                    summaryModel.setPassRate(new BigDecimal(passCount.get()).divide(totalSizeCount, 4, RoundingMode.HALF_UP).multiply(percent));
                    summaryModel.setNoPassRate(new BigDecimal(noPassCount.get()).divide(totalSizeCount, 4, RoundingMode.HALF_UP).multiply(percent));
                    summaryModel.setQualifiedRate(summaryModel.getBestRate().add(summaryModel.getWellRate()).add(summaryModel.getPassRate()));
                    summaryModels.add(summaryModel);
                }
            }

        });
        return summaryModels;
    }

    @Override
    public List<TestResult> listByPlanIdAndStudyCodes(Integer planId, Collection<String> studyCodes) {
        Plan plan = planService.getById(planId);
        Integer templateId = plan.getTemplateId();
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(TestResult::getPlanId, planId);
        wrapper.lambda().in(TestResult::getStudyCode, studyCodes);
        List<TestResult> testResults = list(wrapper);
        if (!CollectionUtils.isEmpty(testResults)) {
            testResults.forEach(testResult -> {
                SysHealthProject healthProject = healthProjectService.listByPrjCodeAndGradeId(testResult.getPrjName(), testResult.getGradeId().toString(), templateId);
                if (healthProject != null) {
                    testResult.setPrjWeight(healthProject.getPrjWeight());
                }
            });
        }
        return testResults;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean calculate(TestResult testResult) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        if (testResult.getSchoolId() != null) {
            wrapper.lambda().eq(TestResult::getSchoolId, testResult.getSchoolId());
        }
        if (StringUtils.hasLength(testResult.getName())) {
            wrapper.lambda().eq(TestResult::getName, testResult.getName());
        }
        if (StringUtils.hasLength(testResult.getStudyCode())) {
            wrapper.lambda().eq(TestResult::getStudyCode, testResult.getStudyCode());
        }
        if (StringUtils.hasLength(testResult.getSex())) {
            wrapper.lambda().eq(TestResult::getSex, testResult.getSex());
        }
        if (StringUtils.hasLength(testResult.getPrjCode())) {
            wrapper.lambda().eq(TestResult::getPrjCode, testResult.getPrjCode());
        }
        if (StringUtils.hasLength(testResult.getPrjName())) {
            wrapper.lambda().like(TestResult::getPrjName, testResult.getPrjName());
        }
        if (testResult.getGradeId() != null) {
            wrapper.lambda().eq(TestResult::getGradeId, testResult.getGradeId());
        }
        wrapper.lambda().eq(TestResult::getPlanId, testResult.getPlanId());
        List<TestResult> testResultList = list(wrapper);
        if(CollectionUtils.isEmpty(testResultList)){
            summaryResultService.clearSummaryResult(testResult);
        } else {
            buildScoreLevel(testResultList, testResult.getPlanId());
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean clearData(TestResult queryParam) {
        if (queryParam.getPlanId() == null) {
            throw new CommonException("缺少计划ID参数");
        }

        QueryWrapper<TestResult> resultQueryWrapper = new QueryWrapper<>();
        resultQueryWrapper.lambda().eq(TestResult::getPlanId, queryParam.getPlanId());
        if (queryParam.getSchoolId() != null) {
            resultQueryWrapper.lambda().eq(TestResult::getSchoolId, queryParam.getSchoolId());
        }
        remove(resultQueryWrapper);

        QueryWrapper<SummaryResult> summaryQueryWrapper = new QueryWrapper<>();
        summaryQueryWrapper.lambda().eq(SummaryResult::getPlanId, queryParam.getPlanId());
        if (queryParam.getSchoolId() != null) {
            summaryQueryWrapper.lambda().eq(SummaryResult::getSchoolId, queryParam.getSchoolId());
        }
        summaryResultService.remove(summaryQueryWrapper);


        return true;
    }

    @Override
    public void removeByPlanIdAndStudyCodeAndPrjNames(Integer planId, String studyCode, Set<String> prjNames) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(TestResult::getStudyCode, studyCode);
        wrapper.lambda().eq(TestResult::getPlanId, planId);
        wrapper.lambda().in(TestResult::getPrjName, prjNames);
        remove(wrapper);
    }

    @Override
    public void updateStudentInfo(Integer planId) {
        this.baseMapper.updateStudentInfo(planId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateParentPlanTest(TestResult testResult) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        if (testResult.getSchoolId() != null) {
            wrapper.lambda().eq(TestResult::getSchoolId, testResult.getSchoolId());
        }
        if (StringUtils.hasLength(testResult.getName())) {
            wrapper.lambda().eq(TestResult::getName, testResult.getName());
        }
        if (StringUtils.hasLength(testResult.getStudyCode())) {
            wrapper.lambda().eq(TestResult::getStudyCode, testResult.getStudyCode());
        }
        if (StringUtils.hasLength(testResult.getSex())) {
            wrapper.lambda().eq(TestResult::getSex, testResult.getSex());
        }
        if (StringUtils.hasLength(testResult.getPrjCode())) {
            wrapper.lambda().eq(TestResult::getPrjCode, testResult.getPrjCode());
        }
        if (StringUtils.hasLength(testResult.getPrjName())) {
            wrapper.lambda().like(TestResult::getPrjName, testResult.getPrjName());
        }
        if (testResult.getGradeId() != null) {
            wrapper.lambda().eq(TestResult::getGradeId, testResult.getGradeId());
        }
        wrapper.lambda().eq(TestResult::getPlanId, testResult.getPlanId());
        List<TestResult> testResultList = list(wrapper);

        Plan plan = planService.getById(testResult.getPlanId());
        if (plan.getParentId() != null && !plan.getParentId().equals(0)) {
            Integer parentId = plan.getParentId();
            Plan parentPlan = planService.getById(parentId);
            Map<String, List<TestResult>> testResultMap = testResultList.stream().collect(Collectors.groupingBy(TestResult::getStudyCode));
            testResultMap.forEach((studyCode, testResults) -> {
                UpdateParentResultModel updateParentResultModel = new UpdateParentResultModel();
                updateParentResultModel.setStudyCode(studyCode);
                updateParentResultModel.setParentPlan(parentPlan);
                updateParentResultModel.setTestResultList(testResults);
                applicationContext.publishEvent(new UpdateParentResultEvent(this, updateParentResultModel));
            });
        }

        return true;
    }

    @Override
    public List<TestResult> listByPlanIdAndPrjNamesAndStudyCode(Integer parentPlanId, Set<String> projectNames, String studyCode) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(TestResult::getStudyCode, studyCode);
        wrapper.lambda().eq(TestResult::getPlanId, parentPlanId);
        wrapper.lambda().in(TestResult::getPrjName, projectNames);
        return list(wrapper);
    }

    @Override
    public List<TestResult> listByPlanId(Integer planId) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(TestResult::getPlanId, planId);
        return list(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean retry(Long retryId) {
        CalculateLog calculateLog = calculateLogService.getById(retryId);
        if(calculateLog != null){
            List<ImportTestResultParam> testResultParamList = JSON.parseArray(calculateLog.getReqParam(),ImportTestResultParam.class);
            calculateTestResult(testResultParamList,calculateLog.getPlanId(),calculateLog.getType());
        }
        return true;
    }

    @Override
    public List<TestResult> listByPlanIdAndStudyCode(String studyCode, Integer planId) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(TestResult::getStudyCode, studyCode);
        wrapper.lambda().eq(TestResult::getPlanId, planId);
        List<TestResult> list = list(wrapper);
        buildRecords(list);
        return list;
    }

    @Override
    public ScoreQueryResult queryScoreResult(ScoreQueryResult queryParam) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(TestResult::getPlanId, queryParam.getPlanId());

        if (!StringUtils.hasLength(queryParam.getStudyCode())
                && !StringUtils.hasLength(queryParam.getIdNumber()) && !StringUtils.hasLength(queryParam.getCardNo())) {
            throw new CommonException("请输入查询条件");
        }
        if (StringUtils.hasLength(queryParam.getStudyCode())) {
            wrapper.lambda().eq(TestResult::getStudyCode, queryParam.getStudyCode());
        }
        if (StringUtils.hasLength(queryParam.getIdNumber())) {
            wrapper.lambda().eq(TestResult::getIdNumber, queryParam.getIdNumber());
        }
        if (StringUtils.hasLength(queryParam.getCardNo())) {
            wrapper.lambda().eq(TestResult::getCardNo, queryParam.getCardNo());
        }
        List<TestResult> testResults = list(wrapper);
        if(CollectionUtils.isEmpty(testResults)){
            return null;
        }
        PlanStudent planStudent = planStudentService.queryByPlanIdAndStudyCode(testResults.get(0).getStudyCode(),queryParam.getPlanId());
        ScoreQueryResult scoreQueryResult = new ScoreQueryResult();
        BeanUtils.copyProperties(planStudent,scoreQueryResult);
        if(planStudent.getSchoolId() != null){
            School school = schoolService.getById(planStudent.getSchoolId());
            scoreQueryResult.setSchoolName(school.getName());
        }
        Plan plan = planService.getById(queryParam.getPlanId());
        SummaryResult summaryResult = summaryResultService.queryStudyCodeAndPlanId(testResults.get(0).getStudyCode(),queryParam.getPlanId());
        Map<String,List<TestResult>> finalResultMap = testResults.stream().collect(Collectors.groupingBy(TestResult::getPrjName));
        if(planStudent.getGradeId() != null){
            scoreQueryResult.setGradeName(GradeUtil.getGradeName(planStudent.getGradeId()));
            String projectNames = testProjectConfig.getProjectMap().get(planStudent.getGradeId() + "_" + scoreQueryResult.getSex());
            List<String> projectNameList = Arrays.asList(projectNames.split(","));
            List<TestResult> finalResultList = new ArrayList<>();
            projectNameList.forEach(projectName -> {
                String prjName = projectName;
                if(projectName.equals("身高体重")){
                    List<TestResult> prjResults = finalResultMap.getOrDefault(prjName, null);
                    if(CollectionUtils.isEmpty(prjResults)){
                        prjName = "BMI";
                    }
                }
                List<TestResult> prjResults = finalResultMap.getOrDefault(prjName, null);
                if (!CollectionUtils.isEmpty(prjResults)) {
                    if(StringUtils.hasLength(plan.getCameraIp())){
                        String webRtcIp = plan.getCameraIp().replaceAll("https","webrtcs");
                        String webRtcUrl = webRtcIp + ":443?username=123&password=e10adc3949ba59abbe56e057f20f883e&cameraID=" + prjResults.get(0).getCameraId();
                        prjResults.get(0).setVideoUrl(webRtcUrl);
                    }
                    finalResultList.add(prjResults.get(0));
                } else {
                    TestResult testResult = new TestResult();
                    testResult.setPrjName(projectName);
                    testResult.setResult("—");
                    testResult.setScore(BigDecimal.ZERO);
                    testResult.setFinalScore(BigDecimal.ZERO);
                    testResult.setLevel("—");
                    finalResultList.add(testResult);
                }
            });
            scoreQueryResult.setTestResultList(finalResultList);
            scoreQueryResult.setSummaryResult(summaryResult);
        }
        return scoreQueryResult;
    }

    private void removeByPlanIdAndStudyCodes(Integer planId, Set<String> studyCodes) {
        QueryWrapper<TestResult> wrapper = new QueryWrapper<>();
        wrapper.lambda().in(TestResult::getStudyCode, studyCodes);
        wrapper.lambda().eq(TestResult::getPlanId, planId);
        remove(wrapper);
    }

    private void buildRecords(List<TestResult> records) {
        if (!CollectionUtils.isEmpty(records)) {
            Set<Integer> schoolIds = new HashSet<>();
            Set<Integer> planIds = new HashSet<>();
            records.forEach(rec -> {
                schoolIds.add(rec.getSchoolId());
                planIds.add(rec.getPlanId());
            });
            List<Plan> planList = planService.listByIds(planIds);
            Map<Integer, Plan> planMap = planList.stream().collect(Collectors.toMap(Plan::getId, p -> p));
            List<School> schoolList = schoolService.listByIds(schoolIds);
            Map<Integer, School> schoolMap = schoolList.stream().collect(Collectors.toMap(School::getId, s -> s));
            records.forEach(rec -> {
                Plan plan = planMap.get(rec.getPlanId());
                SysHealthProject healthProject = healthProjectService.listByPrjCodeAndGradeId(rec.getPrjName(), String.valueOf(rec.getGradeId()), plan.getTemplateId());
                String prjKey = rec.getGradeId() + "_" + rec.getSex();
                String prjNames = testProjectConfig.getProjectMap().get(prjKey);
                if (StringUtils.hasLength(prjNames)) {
                    String[] prjNameList = prjNames.split(",");
                    rec.setTestProcess((double) (records.size() / prjNameList.length));
                }
                if (healthProject != null) {
                    rec.setPrjWeight(healthProject.getPrjWeight());
                }
                if (StringUtils.hasLength(rec.getResultType()) && rec.getResult() == null) {
                    rec.setResult(rec.getResultType());
                }
                rec.setSchoolName(schoolMap.getOrDefault(rec.getSchoolId(), new School()).getName());
            });
        }
    }

    private void buildScoreLevel(List<TestResult> testResults, Integer planId) {

        Plan plan = planService.getById(planId);
        Integer templateId = plan.getTemplateId();
        Map<TestResultKey, List<TestResult>> testResultKeyListMap = testResults.stream().collect(Collectors.groupingBy(t -> new TestResultKey(t.getPrjName(), t.getSex(), t.getGradeId().toString())));

        List<Standard> templateStandardList = standardService.listByTemplateId(templateId);
        List<SysHealthProject> templateProjects = healthProjectService.listByTemplateId(templateId);
        Map<TestResultKey, List<Standard>> standardMap = templateStandardList.stream().collect(Collectors.groupingBy(t -> new TestResultKey(t.getProjectName(), t.getSex(), t.getGradeId())));
        Map<String, SysHealthProject> projectMap = templateProjects.stream().collect(Collectors.toMap(t -> t.getProjectName() + "_" + t.getGradeId(), p -> p));

        testResultKeyListMap.forEach((resultKey, testResultList) -> {
            List<Standard> standardList = standardMap.getOrDefault(resultKey, null);
            SysHealthProject healthProject = projectMap.getOrDefault(resultKey.getPrjName() + "_" + resultKey.getGradeId(), null);
            if (!CollectionUtils.isEmpty(standardList)) {
                Set<String> studyCodes = new HashSet<>();
                testResultList.forEach(testResult -> {
                    studyCodes.add(testResult.getStudyCode());
                    if (testResult.getResult() != null) {
                        ScoreResult scoreResult = standardService.buildScoreResult(testResult.getResult(), standardList, healthProject, plan.getCalculateType(), healthProject.getRadixLength());
                        if (scoreResult != null) {
                            if (scoreResult.getScore() != null) {
                                testResult.setScore(new BigDecimal(scoreResult.getScore().toString()));
                                testResult.setStandardScore(scoreResult.getStandardScore());
                                testResult.setExtraScore(scoreResult.getExtraScore());
                                testResult.setLevel(scoreResult.getLevel());
                                if (healthProject.getPrjWeight() != null) {
                                    if (scoreResult.getExtraScore().compareTo(BigDecimal.ZERO) > 0) {
                                        BigDecimal finalScore = scoreResult.getScore().subtract(scoreResult.getExtraScore());
                                        testResult.setFinalScore(finalScore.multiply(healthProject.getPrjWeight()).add(scoreResult.getExtraScore()));
                                    } else {
                                        testResult.setFinalScore(scoreResult.getScore().multiply(healthProject.getPrjWeight()).add(scoreResult.getExtraScore()));
                                    }
                                }
                            } else {
                                testResult.setScore(BigDecimal.ZERO);
                                testResult.setStandardScore(BigDecimal.ZERO);
                                testResult.setExtraScore(BigDecimal.ZERO);
                                testResult.setFinalScore(BigDecimal.ZERO);
                                testResult.setLevel("不及格");
                            }
                        }
                    }
                });
                boolean saveOk = updateBatchById(testResultList);
                if (saveOk) {
                    List<TestResult> countTestResultList = listByPlanIdAndStudyCodes(planId, studyCodes);
                    summaryResultService.batchSummaryResult(countTestResultList);
                }
            }
        });
    }
}
